package com.zzzzzz.app.account.dao;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import com.zzzzzz.app.account.NoSuchUserException;
import com.zzzzzz.app.account.model.po.User;
import com.zzzzzz.common.util.StringPool;
import com.zzzzzz.core.dao.BaseDao;
import com.zzzzzz.core.exception.SystemException;

@Repository
public class UserDao extends BaseDao {

	private static final String FIND_ALL = "select * from user_";
	
	private static final String ADD = "insert into user_(user_id, username, email, password, create_date, status_) values(:userId, :username, :email, :password, :createDate, :status)";
	
	private static final String EDIT_PROFILE_BASIC = "update user_ set first_name = :firstName, last_name = :lastName, username = :username, about_me = :aboutMe, gender = :gender, dob = :dob where user_id = :userId";
	
	private static final String EDIT_PROFILE_CONTACT = "update user_ set website = :website where user_id = :userId";
	
	private static final String EDIT_PORTRAIT = "update user_ set portrait = ? where user_id = ?";
	
	private static final String EDIT_PASSWORD = "update user_ set password = :newPassword where user_id = :userId and password = :currentPassword";
	
	private static final String RESET_PASSWORD = "update user_ set password = :newPassword where user_id = :userId";
	
	private static final String EDIT_EMAIL = "update user_ set email = :email where user_id = :userId and password = :password";
	
	private static final String EDIT_STATUS = "update user_ set status_ = :status where user_id = :userId";
	
	private static final String FIND_BY_ID = "select * from user_ where user_id = ?";
	
	private static final String FIND_BY_EMAIL = "select * from user_ where email = ?";
	
	private static final String FIND_ALL_COUNT = "select count(*) from user_";
	
	private static final String FIND_ALL_LIMIT = "SELECT * FROM user_ ORDER BY create_date DESC LIMIT ?, ?";

	private static final String _NO_SUCH_ENTITY_WITH_PRIMARY_KEY = "No User exists with the primary key ";
	
	private static final String _NO_SUCH_ENTITY_WITH_KEY = "No User exists with the key {";

	protected class UserRowMapper implements RowMapper<User> {
		public User mapRow(ResultSet rs, int rn) throws SQLException {
			User user = new User();
			user.setUserId(rs.getLong("user_id"));
			user.setUsername(rs.getString("username"));
			user.setEmail(rs.getString("email"));
			user.setPassword(rs.getString("password"));
			user.setFirstName(rs.getString("first_name"));
			user.setLastName(rs.getString("last_name"));
			user.setPortrait(rs.getString("portrait"));
			user.setStatus(rs.getInt("status_"));
			user.setAboutMe(rs.getString("about_me"));
			user.setDob(rs.getDate("dob"));
			user.setCreateDate(rs.getTimestamp("create_date"));
			user.setWebsite(rs.getString("website"));
			user.setGender(rs.getString("gender"));
			return user;
		}
	}
	
	public void add(User user) throws SystemException {
		long userId = updateForLongKey(ADD, user);
		user.setUserId(userId);
	}

	public void editStatus(Long userId,Integer status) {
		Map<String, Object> args = new HashMap<String, Object>();
		args.put("status", status);
		args.put("userId", userId);
		update(EDIT_STATUS, args);
	}

	public void editProfileBasic(User user) {
		Map<String, Object> args = new HashMap<String, Object>();
		args.put("firstName", user.getFirstName());
		args.put("lastName", user.getLastName());
		args.put("username", user.getUsername());
		args.put("aboutMe", user.getAboutMe());
		args.put("dob", user.getDob());
		args.put("gender", user.getGender());
		args.put("userId", user.getUserId());
		update(EDIT_PROFILE_BASIC, args);
	}
	
	public void editProfileContact(User user) {
		Map<String, Object> args = new HashMap<String, Object>();
		args.put("website", user.getWebsite());
		args.put("userId", user.getUserId());
		update(EDIT_PROFILE_CONTACT, args);
	}
	
	public void editPortrait(Long userId, String portrait) {
		update(EDIT_PORTRAIT, portrait);
	}
	
	public void editPassword(Long userId, String currentPassword, String newPassword) {
		Map<String, Object> args = new HashMap<String, Object>();
		args.put("currentPassword", currentPassword);
		args.put("newPassword", newPassword);
		args.put("userId", userId);
		update(EDIT_PASSWORD, args);
	}
	
	public void resetPassword(Long userId, String newPassword) {
		Map<String, Object> args = new HashMap<String, Object>();
		args.put("newPassword", newPassword);
		args.put("userId", userId);
		update(RESET_PASSWORD, args);
	}
	
	public void editEmail(Long userId, String email, String password) {
		Map<String, Object> args = new HashMap<String, Object>();
		args.put("email", email);
		args.put("password", password);
		args.put("userId", userId);
		update(EDIT_EMAIL, args);
	}
	
	public User findById(Long userId) throws NoSuchUserException, SystemException {
		User user = null;
		try{
			user = findOne(FIND_BY_ID, new UserRowMapper(), userId);
		}catch(Exception e) {
			throw processException(e);
		}
		if(user == null) {
			throw new NoSuchUserException(_NO_SUCH_ENTITY_WITH_PRIMARY_KEY + userId);
		}
		return user;
	}

	public User findByEmail(String email) throws SystemException, NoSuchUserException {
		User user = null;
		try{
			user = findOne(FIND_BY_EMAIL, new UserRowMapper(), email);
		}catch(Exception e) {
			throw processException(e);
		}
		if(user == null) {
			throw new NoSuchUserException(_NO_SUCH_ENTITY_WITH_KEY + "email=" + email + StringPool.CLOSE_CURLY_BRACE);
		}
		return user;
	}
	
	public List<User> findUserList(int start, int offset) throws SystemException {
		try{
			return findList(FIND_ALL_LIMIT, new UserRowMapper(), start, offset);
		}catch(Exception e) {
			throw processException(e);
		}
	}
	
	public int findALLCount() throws SystemException {
		try{
			return findInt(FIND_ALL_COUNT);
		}catch(Exception e) {
			throw processException(e);
		}
	}
	
}
